home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / master / Examples / Visual / VOpts / gadgets.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-02-01  |  45.4 KB  |  1,213 lines

  1. #include "vopts.h"
  2.  
  3. Prototype int  init_gadgets(void);
  4. Prototype void free_gadget(struct Gadget *gadget);
  5. Prototype void free_gadlist(struct GADLIST *gadlist);
  6. Prototype int  set_group_gadgets(void);
  7. Prototype void set_fr_gadgets(char *frtext);
  8. Prototype void clear_fr_gadgets(void);
  9. Prototype struct Gadget *create_gadget(struct GADLIST *gadlist,struct G_OBJECT *object,int ulx, int uly,int width);
  10. Prototype void setup_string_gadget(struct Gadget *gad,int base);
  11. Prototype struct Gadget *setup_cycle_gadget(struct Gadget *gad,struct IntuiText *itext,struct G_VALUE *val);
  12. Prototype void reset_list_object(struct G_LIST *list,int active);
  13. Prototype int  setup_list_object(struct GADLIST *gadlist,struct Gadget *gad);
  14. Prototype struct GADLIST *layout_gadgets(struct G_OBJECT *objlist, int group, int ulx, int uly, int width);
  15. Prototype struct Border *build_border(int width, int height, int mode);
  16. Prototype int  init_gad_sizes(void);
  17. Prototype void get_cycle_sizes(struct G_OBJECT *objlist, int *titsize,  int *cycsize, int *fudgesize);
  18. Prototype int  text_width(char *str);
  19. Prototype int string_width(char *str, int def_size);
  20.  
  21. /***********************************************************************************
  22.  * Procedure: init_gadgets
  23.  * Synopsis:  rc = init_gadgets();
  24.  * Purpose:   Set up all the base system gadgets for the window.  This includes all
  25.  *            The user defined gadgets as well as the three buttons on the bottom
  26.  ***********************************************************************************/
  27. int init_gadgets()
  28. {
  29.    struct Gadget *gad;
  30.    struct Border *border;
  31.    struct IntuiText *itext;
  32.    int ulx, uly;
  33.    int i;
  34.  
  35.    global.gadlist = layout_gadgets(global.objects, 0,
  36.                                     global.ri.WindowLeft,
  37.                                     global.ri.WindowTitle,
  38.                                     global.cycsize[0]+global.titsize[0]
  39.                                     );
  40.    if (global.gadlist == NULL) return(1);
  41.    ulx = global.ri.WindowLeft;
  42.    uly = global.height - global.ri.WindowBottom - global.iheight;
  43.  
  44.    for(i = 0; i < 3; i++)
  45.    {
  46.       global.button[i].class = CLASS_BUTTON;
  47.       global.button[i].state = i; /* Note that these values correspond to */
  48.                                    /* the BUTTON_xxx equates               */
  49.  
  50.       gad = create_gadget(NULL, global.button+i, ulx, uly, BUTTON_WIDTH);
  51.  
  52.       if (gad == NULL) return(1);
  53.       gad->GadgetRender = build_border(BUTTON_WIDTH,
  54.                                        global.iheight, MODE_OUT);
  55.  
  56.       itext = gad->GadgetText;
  57.       itext->LeftEdge += (BUTTON_WIDTH - IntuiTextLength(itext))/2;
  58.  
  59.       gad->NextGadget = global.gadlist->gadgets;
  60.       global.gadlist->gadgets = gad;
  61.       global.gadlist->count++;
  62.  
  63.       gad->GadgetType = BOOLGADGET;
  64.  
  65.       ulx += (global.width - (global.ri.WindowLeft  +
  66.                                global.ri.WindowRight +
  67.                                (3*BUTTON_WIDTH)
  68.                               )
  69.              ) / 2 + BUTTON_WIDTH;
  70.    }
  71.  
  72.    /* Calculate the limits for the box that holds the gadgets */
  73.    global.boxw = global.cycsize[1] + global.titsize[1] +
  74.                   MARGIN_LEFT + MARGIN_RIGHT;
  75.    global.boxx = global.width - global.ri.WindowRight - global.boxw;
  76.  
  77.    global.boxy = global.ri.WindowTitle + DHBAR;
  78.    global.boxh = uly - MARGIN_MID - DVBAR - global.boxy;
  79.  
  80.    for (i = 2; i >= 0; i -= 2)
  81.    {
  82.       /* We also need to attach a box around the other area.  Since we don't want to */
  83.       /* Have to constantly create/recreate it, we can get away with putting it on   */
  84.       /* the first button.                                                           */
  85.       border = build_border(global.boxw + DVBAR + i*2,
  86.                             global.boxh + DHBAR + i,
  87.                             i ? MODE_IN : MODE_OUT);
  88.       if (border != NULL)
  89.       {
  90.          border->NextBorder->LeftEdge =
  91.          border->LeftEdge = (global.boxx - VBAR - i       ) - gad->LeftEdge;
  92.          border->NextBorder->TopEdge =
  93.          border->TopEdge  = (global.boxy - HBAR - (i >> 1)) - gad->TopEdge;
  94.          border->NextBorder->NextBorder = gad->GadgetRender;
  95.          gad->GadgetRender = border;
  96.       }
  97.    }
  98.  
  99.    global.boxx += MARGIN_LEFT;
  100.    global.boxy += MARGIN_TOP-DHBAR;
  101.    global.boxw -= (MARGIN_LEFT+MARGIN_RIGHT);
  102.    global.boxh -= (MARGIN_TOP-DHBAR+MARGIN_BOTTOM);
  103.  
  104.    /* now setup stuff for default file requester gadgets */
  105.    for (i = 0; i < 2; i++)
  106.    {
  107.       global.frbutton[i].class = CLASS_BUTTON;
  108.       global.frbutton[i].state = BUTTON_FRSAVE + i;
  109.       /* this is a shameless trick to skip the normal middle button */
  110.       global.frbutton[i].title = global.button[2*i].title;
  111.  
  112.       global.frbutton[i].title =
  113.          global.text[i == 0 ? TEXT_OK : TEXT_CANCEL];
  114.    }
  115.    global.frstring.base.class = CLASS_STRING;
  116.    global.frstring.base.title = global.text[TEXT_FILEREQ];
  117.  
  118.    return(set_group_gadgets());
  119. }
  120. /***********************************************************************************
  121.  * Procedure: free_gadget
  122.  * Synopsis:  free_gadget(gadget)
  123.  * Purpose:   Free up all memory associated with a gadget
  124.  ***********************************************************************************/
  125. void free_gadget(struct Gadget *gadget)
  126. {
  127.    struct G_OBJECT *obj;
  128.  
  129.    if (gadget)
  130.    {
  131.       obj = (struct G_OBJECT *)(gadget->UserData);
  132.  
  133.       obj->gadget = NULL;
  134.  
  135.       if (obj->class == CLASS_STRING)
  136.       {
  137.          /* We need to free the border structure also */
  138.       }
  139.       free_mem(gadget, sizeof(struct Gadget)+sizeof(struct IntuiText));
  140.    }
  141. }
  142.  
  143. /***********************************************************************************
  144.  * Procedure: free_gadlist
  145.  * Synopsis:  free_gadlist(gadlist)
  146.  * Purpose:   Free up all memory associated with a gadget list created by
  147.  *            layout_gadgets
  148.  ***********************************************************************************/
  149. void free_gadlist(struct GADLIST *gadlist)
  150. {
  151.    struct Gadget *gad, *nextgad;
  152.    struct G_CYCLE *cyc;
  153.    struct G_STRING *str;
  154.  
  155.    for(gad = gadlist->gadgets; gad && gadlist->count; gad = nextgad, gadlist->count--)
  156.    {
  157.       nextgad = gad->NextGadget;
  158.       cyc = (struct G_CYCLE *)gad->UserData;
  159.  
  160.       if (cyc->base.class == CLASS_CYCLE)
  161.       {
  162.          /* If there is a string gadget currently in the cycle gadget, we need */
  163.          /* to free it up                                                      */
  164.          if ((str = cyc->curval->string) != NULL)
  165.          {
  166.             free_gadget(str->base.gadget);
  167.          }
  168.       }
  169.       free_gadget(gad);
  170.    }
  171.  
  172.    free_mem(gadlist, sizeof(struct GADLIST));
  173. }
  174.  
  175. /***********************************************************************************
  176.  * Procedure: set_group_gadgets
  177.  * Synopsis:  set_group_gadgets();
  178.  * Purpose:   Create the gadgetry for
  179.  ***********************************************************************************/
  180. int set_group_gadgets()
  181. {
  182.    struct G_OBJECT *next;
  183.  
  184.    if (global.grpgadlist)
  185.    {
  186.       /* We need to take this off the system gadget list and then free up */
  187.       /* all the storage associated with it                               */
  188.       set_gadlist(global.grpgadlist, 0);
  189.       free_gadlist(global.grpgadlist);
  190.  
  191.       global.grpgadlist = NULL;
  192.    }
  193.  
  194.    if (global.rp)
  195.    {
  196.       /* Wipe out the inner area of the gadget so that we can redraw it later */
  197.       SetBPen(global.rp, 0);
  198.       SetAPen(global.rp, 0);
  199.       RectFill( global.rp, global.boxx, global.boxy,
  200.                             global.boxx+global.boxw, global.boxy+global.boxh);
  201.    }
  202.  
  203.    next = global.curgroup->base.next;
  204.    global.curgroup->base.next = global.curgroup->objects;
  205.    global.grpgadlist = layout_gadgets((struct G_OBJECT *)global.curgroup, 1,
  206.                                     global.boxx, global.boxy, global.boxw);
  207.    global.curgroup->base.next = next;
  208.  
  209.    set_gadlist(global.grpgadlist, 1);
  210.  
  211.    return(0);
  212. }
  213.  
  214. /***********************************************************************************
  215.  * Procedure: set_fr_gadgets
  216.  * Synopsis:  set_fr_gadgets(text);
  217.  * Purpose:   setup the string gadget and buttons for the default file requester
  218.  *            to use when AmigaDos 2.0 is not present.  Text is initial string
  219.  *            gadget text
  220.  ***********************************************************************************/
  221.  
  222. void set_fr_gadgets(char *frtext)
  223. {
  224.    int ulx, uly, i;
  225.    struct Gadget *gad;
  226.    struct IntuiText *itext;
  227.  
  228.    /* Need to see if requester already displayed an exit if so.  */
  229.    if (global.frgadlist != NULL) return;
  230.  
  231.    set_gadgets(0);
  232.    SetBPen(global.rp, 0);
  233.    SetAPen(global.rp, 0);
  234.    RectFill( global.rp, global.ri.WindowLeft,
  235.                         global.ri.WindowTitle,
  236.                         global.width - global.ri.WindowRight + 4,
  237.                         global.height - global.ri.WindowBottom);
  238.  
  239.    strncpy(global.frstring.buf, frtext, MAX_STRING);
  240.    /* make sure string is null terminated */
  241.    global.frstring.buf[MAX_STRING-1] = 0;
  242.    global.frgadlist = layout_gadgets((struct G_OBJECT *)&global.frstring, 2,
  243.                  global.ri.WindowLeft,
  244.                  global.ri.WindowTop + (global.height - global.iheight)/2,
  245.                  global.width);
  246.  
  247.    if (global.frgadlist == NULL) return;
  248.  
  249.    ulx = global.ri.WindowLeft;
  250.    uly = global.height - global.ri.WindowBottom - global.iheight;
  251.  
  252.    /* Create the buttons here */
  253.    for(i = 0; i < 2; i++)
  254.    {
  255.       gad = create_gadget(global.frgadlist, global.frbutton+i,
  256.                           ulx, uly, BUTTON_WIDTH);
  257.  
  258.       if (gad == NULL) return;
  259.       gad->GadgetRender = build_border(BUTTON_WIDTH,
  260.                                        global.iheight, MODE_OUT);
  261.  
  262.       itext = gad->GadgetText;
  263.       itext->LeftEdge += (BUTTON_WIDTH - IntuiTextLength(itext))/2;
  264.  
  265.       gad->GadgetType = BOOLGADGET;
  266.       ulx = global.width - (global.ri.WindowRight + BUTTON_WIDTH);
  267.    }
  268.    set_gadlist(global.frgadlist, 1);
  269.  
  270. }
  271.  
  272. /***********************************************************************************
  273.  * Procedure: clear_fr_gadgets
  274.  * Synopsis:  clear_fr_gadgets();
  275.  * Purpose:   remove the default requester stuff and redisplay the normal
  276.  *            VOPTS gadgets.
  277.  ***********************************************************************************/
  278.  
  279. void clear_fr_gadgets(void)
  280. {
  281.    if (global.frgadlist != NULL)
  282.    {
  283.       set_gadlist(global.frgadlist, 0);
  284.       /* Free the gadlist */
  285.       free_gadlist(global.frgadlist);
  286.       global.frgadlist = NULL;
  287.       SetBPen(global.rp, 0);
  288.       SetAPen(global.rp, 0);
  289.       RectFill( global.rp, global.ri.WindowLeft,
  290.                         global.ri.WindowTitle,
  291.                         global.width - global.ri.WindowRight,
  292.                         global.height - global.ri.WindowBottom);
  293.  
  294.    }
  295.    set_gadgets(1);
  296.  
  297. }
  298. /***********************************************************************************
  299.  * Procedure: create_gadget
  300.  * Synopsis:  Gadget = create_gadget(gadlist, object, ulx, uly, width)
  301.  * Purpose:   Create all the appropriate gadgetry and image structures for a list
  302.  *            of gadgets.
  303.  ***********************************************************************************/
  304. struct Gadget *create_gadget(struct GADLIST *gadlist,
  305.                              struct G_OBJECT *object,
  306.                              int ulx, int uly,
  307.                              int width
  308.                             )
  309. {
  310.    struct Gadget *gad;
  311.    struct IntuiText *itext;
  312.  
  313.  
  314.    /* Create a gadget structure and an associated intuitext structure to be */
  315.    /* Layed out on the screen                                               */
  316.    gad = (struct Gadget *)get_mem(sizeof(struct Gadget)+sizeof(struct IntuiText));
  317.    if (gad)
  318.    {
  319.       itext = (struct IntuiText *)(gad+1);
  320.  
  321.       gad->LeftEdge    = ulx;
  322.       gad->TopEdge     = uly;
  323.       gad->Width       = width;
  324.       gad->Height      = global.iheight;
  325.       gad->Flags       = GADGHCOMP;
  326.       gad->Activation  = RELVERIFY;
  327.       gad->GadgetText  = itext;
  328.       gad->UserData    = (APTR)object;
  329.       gad->GadgetID    = object->class;
  330.       object->gadget      = gad;
  331.  
  332.       /* Now we fill in the Intuitext structure */
  333.       itext->FrontPen  = 1;
  334.       itext->BackPen   = 0;
  335.       itext->DrawMode  = JAM1;
  336.       itext->LeftEdge  = 0;
  337.       itext->TopEdge   = (global.iheight - global.ri.FontSize) / 2;
  338.       itext->ITextFont = &global.ri.TextAttr;
  339.       itext->IText     = object->title;
  340.       itext->NextText  = NULL;
  341.  
  342.       if (gadlist)
  343.       {
  344.          gad->NextGadget = gadlist->gadgets;
  345.          gadlist->gadgets = gad;
  346.          gadlist->count++;
  347.       }
  348.    }
  349.  
  350.    return(gad);
  351. }
  352.  
  353. /***********************************************************************************
  354.  * Procedure: setup_string_gadget
  355.  * Synopsis:  setup_string_gadget(gad, string, ulx, uly, width, base)
  356.  * Purpose:   Create all the appropriate gadgetry and image structures for a list
  357.  *            of gadgets.
  358.  ***********************************************************************************/
  359. void setup_string_gadget(struct Gadget *gad,
  360.                          int base
  361.                         )
  362. {
  363.    int wraps;
  364.    int i;
  365.    struct Border *border;
  366.    struct StringInfo *si;
  367.    int sluff;
  368.  
  369.    if (gad == NULL) return;
  370.  
  371.    wraps = (base == CLASS_STRING) ? 2 : 1;
  372.  
  373.    gad->LeftEdge += VBAR*wraps;
  374.    gad->TopEdge  += DHBAR;
  375.    gad->Width    -= DVBAR*wraps;
  376.    gad->Height   -= 2*DHBAR;
  377.  
  378.    sluff = (gad->Height - global.ri.FontSize);
  379.    if (sluff < 0) sluff = 0;
  380.    gad->Height  = global.ri.FontSize;
  381.    gad->TopEdge += sluff / 2;
  382.    if (gad->GadgetText)
  383.    {
  384.       gad->GadgetText->TopEdge -= (DHBAR+sluff);
  385.       gad->GadgetText->LeftEdge -= VBAR*wraps;
  386.    }
  387.  
  388.    if ((base == CLASS_LIST)   ||
  389.        (base == CLASS_STRING) ||
  390.        (base == CLASS_CYCLE))
  391.    {
  392.       for(i=wraps; i > 0; i--)
  393.       {
  394.          /* We need to put a border around the gadget. */
  395.          /* For some string gadgets, we only need a single border */
  396.          /* We can tell this by the base type */
  397.          border = build_border(gad->Width+4*i, gad->Height + sluff + 2*i,
  398.                                (i == 1) ? MODE_IN : MODE_OUT);
  399.          if (border != NULL)
  400.          {
  401.             border->NextBorder->LeftEdge = border->LeftEdge = -2*i;
  402.             border->NextBorder->TopEdge  = border->TopEdge  = -1*i - (sluff/2);
  403.             border->NextBorder->NextBorder = gad->GadgetRender;
  404.             gad->GadgetRender = border;
  405.          }
  406.       }
  407.    }
  408.  
  409.    /* Lastly, we need to setup up the SpecialInfo structure for the string gadget */
  410.    /* If for some reason this fails, we will turn it into a button gadget         */
  411.    si = (struct StringInfo *)get_mem(sizeof(struct StringInfo));
  412.    if (si != NULL)
  413.    {
  414.       gad->SpecialInfo = (APTR)si;
  415.       gad->GadgetType = STRGADGET;
  416.       si->Buffer = ((struct G_STRING *)(gad->UserData))->buf;
  417.       si->MaxChars = MAX_STRING;
  418.    }
  419.    else
  420.       gad->GadgetType = BOOLGADGET;
  421. }
  422.  
  423.  
  424. /***********************************************************************************
  425.  * Procedure: setup_cycle_gadget
  426.  * Synopsis:  gadget = setup_cycle_gadget(gadget, value)
  427.  * Purpose:   Create any subtending string gadgets and correctly position any
  428.  *            cycle value text
  429.  ***********************************************************************************/
  430. struct Gadget *setup_cycle_gadget(struct Gadget *gad,
  431.                                   struct IntuiText *itext,
  432.                                   struct G_VALUE *val
  433.                                  )
  434. {
  435.    struct Gadget *strgad;
  436.    int ilen;
  437.  
  438.    ilen = IntuiTextLength(itext);
  439.  
  440.    if (val->string)
  441.    {
  442.       int x, width;
  443.  
  444.       itext->LeftEdge = CYC_ICON_WIDTH + 2;
  445.       /* We need to create a string gadget to get the input text from */
  446.  
  447.       x = itext->LeftEdge + ilen;
  448.       width = gad->Width - x - 2;
  449.  
  450.       /* Now, create a string gadget and border to put around the gadget */
  451.       strgad = create_gadget(NULL, (struct G_OBJECT *)val->string,
  452.                                        gad->LeftEdge+x, gad->TopEdge, width);
  453.       if (strgad)
  454.       {
  455.          setup_string_gadget(strgad, CLASS_CYCLE);
  456.       }
  457.    }
  458.    else
  459.    {
  460.       strgad = NULL;
  461.       itext->LeftEdge  = (CYC_ICON_WIDTH + gad->Width - ilen) / 2;
  462.    }
  463.    return(strgad);
  464. }
  465. /***********************************************************************************
  466.  * Procedure: reset_list_object
  467.  * Synopsis:  void reset_list_object(list,active);
  468.  * Purpose:   Initialize all the appropriate text pointers for a list gadget
  469.  ***********************************************************************************/
  470. void reset_list_object(struct G_LIST *list,
  471.                        int active
  472.                       )
  473. {
  474.    struct G_ENTRY *ent;
  475.    int i;
  476.  
  477.    ent = list->top;
  478.  
  479.    /* Run through all the entries visible on the screen and for each */
  480.    /* one that is displayed, mark the gadget as selectable.          */
  481.    for(i = 0; i < MAX_LIST; i++)
  482.    {
  483.       list->btngad[i]->Flags  = (list->btngad[i]->Flags & ~GADGHIGHBITS) |
  484.                                 GADGHNONE;
  485.       list->btngad[i]->Height = global.eheight;
  486.       list->strgad[i]->GadgetRender = NULL;
  487.       /* seems unnecessary, but Dos 1.3 likes to write blanks to unselected */
  488.       /* string gadgets                                                     */
  489.       ((struct StringInfo *)list->strgad[i]->SpecialInfo)->Buffer = global.defbuf;
  490.  
  491.       /* Is there an entry corresponding to this position on the screen? */
  492.       if (ent)
  493.       {
  494.          /* Certainly is an entry, is it where they want a string gadget ? */
  495.          if (i == active)
  496.          {
  497.             /* Yes, shrink the gadget out of existence so that it doesn't  */
  498.             /* appear on the screen.                                       */
  499.             list->btngad[i]->Height = 1;
  500.             list->strgad[i]->GadgetRender = list->sborder;
  501.          }
  502.          else
  503.          {
  504.             list->btngad[i]->Flags = (list->btngad[i]->Flags & ~GADGHIGHBITS) |
  505.                                      GADGHCOMP;
  506.          }
  507.  
  508.          ((struct StringInfo *)
  509.           list->strgad[i]->SpecialInfo)->Buffer = ent->buf;
  510.          ent = (struct G_ENTRY *)ent->base.next;
  511.       }
  512.    }
  513. }
  514.  
  515. /***********************************************************************************
  516.  * Procedure: setup_list_object
  517.  * Synopsis:  ulx = setup_list_object(gadlist, gadget)
  518.  * Purpose:   Create all the appropriate gadgetry and image structures for a list
  519.  *            object
  520.  ***********************************************************************************/
  521. int setup_list_object(struct GADLIST *gadlist,
  522.                       struct Gadget *gad
  523.                      )
  524. {
  525.    int ulx, uly, alen, dlen, ilen;
  526.    struct G_LIST *list;
  527.    int i;
  528.    char *savetitle;
  529.    struct Gadget *slider, *dngad, *upgad, *addgad, *delgad;
  530.    struct PropInfo *pi;
  531.  
  532. #define ARR_HEIGHT  (7+DHBAR)
  533. #define PROP_WIDTH  (14+DVBAR)
  534.  
  535.    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  536.    /* A list object consists of 8 separate gadgets arranged as below*/
  537.    /* 1: Boolean gadgets that overlay string gadgets.  When the     */
  538.    /* 2:   string gadget is to be active, the height of the boolean */
  539.    /* 3:   gadget is set to 1 exposing the string gadget.           */
  540.    /* 4: A slider gadget to allow positioning in the list           */
  541.    /* 5: An up arrow gadget for moving up one item in the list      */
  542.    /* 6: A Down arrow gadget for moving down one item in the list   */
  543.    /* 7: A NEW gadget for creating an entry in front of current item*/
  544.    /* 8: A DEL gadget for removing the current item from the list.  */
  545.    /*                                                               */
  546.    /*                                                               */
  547.    /*  TITLE TEXT                                                   */
  548.    /* ............................................}+---+            */
  549.    /* ::+---------------------------------------+}}|4  |            */
  550.    /* ::|1                                      |}}|   |            */
  551.    /* ::| I T E M 1                             |}}|   |            */
  552.    /* ::+---------------------------------------+}}| _ |+-------+   */
  553.    /* ::+---------------------------------------+}}|[_]||7      |   */
  554.    /* ::|2                                      |}}|   || N E W |   */
  555.    /* ::| I T E M 2                             |}}+---+|       |   */
  556.    /* ::+---------------------------------------+}}|5^ |+-------+   */
  557.    /* ::+---------------------------------------+}}|/ \|+-------+   */
  558.    /* ::|3                                      |}}+---+|8      |   */
  559.    /* ::| I T E M 3                             |}}|\ /|| D E L |   */
  560.    /* ::+---------------------------------------+}}|6V ||       |   */
  561.    /* :}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}+---++-------+   */
  562.    /*                                                               */
  563.    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  564.    list = (struct G_LIST *)gad->UserData;
  565.  
  566.    /* We need to figure out how big the NEW and DEL gadgets will be */
  567.    alen = ilen = text_width(global.button[BUTTON_NEW].title);
  568.    dlen = text_width(global.button[BUTTON_DEL].title);
  569.    if (dlen > ilen) ilen = dlen;
  570.    ilen += 2*DHBAR;
  571.  
  572.    gad->GadgetText->TopEdge   = -global.ri.FontSize;
  573.    gad->TopEdge     += global.ri.FontSize;
  574.    gad->Width       -= ilen + PROP_WIDTH;
  575.    gad->Height       = MAX_LIST*global.eheight + global.listextra;
  576.    gad->Flags        = GADGHNONE;
  577.    gad->GadgetRender = build_border(gad->Width,
  578.                                     gad->Height,
  579.                                     MODE_OUT);
  580.  
  581.    savetitle = list->base.title;
  582.    list->base.title = "";
  583.  
  584.    uly = gad->TopEdge;
  585.    ulx = gad->LeftEdge + gad->Width;
  586.  
  587.    /* Create the slider and two arrow gadgets.  We will steal the  */
  588.    /* first itext structure and throw it on to the main gadget     */
  589.    slider = create_gadget(gadlist, (struct G_OBJECT *)list,
  590.                                   ulx+DVBAR, uly+DHBAR, PROP_WIDTH-2*DVBAR );
  591.    if (slider == NULL) return(0);
  592.    list->slider = slider;
  593.    slider->Height       = global.listextra + MAX_LIST*global.eheight -
  594.                           2*ARR_HEIGHT - 2*DHBAR;
  595.    slider->GadgetID     = CLASS_PROP;
  596.    slider->GadgetType   = PROPGADGET;
  597.    pi = (struct PropInfo *)get_mem(sizeof(struct PropInfo)+
  598.                                            sizeof(struct Image));
  599.    if (pi == NULL) return(0);
  600.    slider->GadgetRender = (struct Image *)(pi+1);
  601.    slider->SpecialInfo  = (APTR)pi;
  602.    pi->Flags = AUTOKNOB | FREEVERT | PROPBORDERLESS;
  603.    recalc_prop(list, &pi->VertBody, &pi->VertPot);
  604.  
  605.    upgad  = create_gadget(gadlist, (struct G_OBJECT *)list,
  606.                                   ulx, uly+slider->Height+2*DHBAR, PROP_WIDTH);
  607.    if (upgad == NULL) return(0);
  608.    upgad->Height       = ARR_HEIGHT;
  609.    upgad->GadgetRender = &global.arrowborder[1];
  610.    upgad->GadgetType   = BOOLGADGET; /* not auto default for Dos 1.3  */
  611.    upgad->GadgetID     = CLASS_UP;
  612.    upgad->GadgetText   = NULL;
  613.  
  614.    dngad  = create_gadget(gadlist, (struct G_OBJECT *)list,
  615.                                   ulx, upgad->TopEdge+ARR_HEIGHT, PROP_WIDTH);
  616.    if (dngad == NULL) return(0);
  617.    dngad->Height       = ARR_HEIGHT;
  618.    dngad->GadgetRender = &global.arrowborder[0];
  619.    dngad->GadgetType   = BOOLGADGET; /* not auto default for Dos 1.3  */
  620.    dngad->GadgetID     = CLASS_DOWN;
  621.    dngad->GadgetText   = NULL;
  622.  
  623.    /* Create the ADD/DEL Buttons                                        */
  624.    addgad = create_gadget(gadlist, (struct G_OBJECT *)list, ulx+PROP_WIDTH,
  625.                                   uly + global.listextra + MAX_LIST*global.eheight-2*global.iheight, ilen);
  626.    if (addgad == NULL) return(0);
  627.    addgad->GadgetRender = build_border(ilen, addgad->Height, MODE_OUT);
  628.    addgad->GadgetType   = BOOLGADGET; /* not auto default for Dos 1.3  */
  629.    addgad->GadgetID     = CLASS_ADD;
  630.    addgad->GadgetText->LeftEdge += (ilen-alen)>>1;
  631.    addgad->GadgetText->IText = global.button[BUTTON_NEW].title;
  632.  
  633.    delgad = create_gadget(gadlist, (struct G_OBJECT *)list, addgad->LeftEdge,
  634.                                        addgad->TopEdge+addgad->Height, ilen);
  635.    if (delgad == NULL) return(0);
  636.    list->delgad = delgad;
  637.    delgad->GadgetRender = addgad->GadgetRender;
  638.    delgad->GadgetType   = BOOLGADGET; /* not auto default for Dos 1.3  */
  639.    delgad->GadgetID     = CLASS_DEL;
  640.    if (list->first == NULL)
  641.       delgad->Flags       |= GADGDISABLED;
  642.    delgad->GadgetText->LeftEdge += (ilen-dlen)>>1;
  643.    delgad->GadgetText->IText = global.button[BUTTON_DEL].title;
  644.  
  645.    for(i = 0; i < MAX_LIST; i++)
  646.    {
  647.       struct Gadget *tgad;
  648.  
  649.       /* Create the string and button gadgets.  Because we insert them on the */
  650.       /* List in reverse order and we want the button gadget to appear first, */
  651.       /* we need to create them in reverse order.                             */
  652.       /* This ordering is assumed in the state changing code.                 */
  653.       tgad = list->strgad[i] = create_gadget(gadlist,
  654.                                              (struct G_OBJECT *)list,
  655.                                              gad->LeftEdge+VBAR, uly,
  656.                                              gad->Width-DVBAR);
  657.       if (tgad == NULL) return(0);
  658.       tgad->GadgetText = NULL;
  659.       tgad->Height = global.eheight;
  660.       setup_string_gadget(tgad, CLASS_LIST+i);
  661.       tgad->GadgetID   = CLASS_STRING;
  662.  
  663.       tgad = list->btngad[i] = create_gadget(gadlist,
  664.                                              (struct G_OBJECT *)list,
  665.                                              gad->LeftEdge+VBAR, uly,
  666.                                              gad->Width-DVBAR);
  667.       if (tgad == NULL) return(0);
  668.       tgad->GadgetType = BOOLGADGET; /* not auto default for Dos 1.3  */
  669.       tgad->Height     = global.eheight;
  670.       tgad->GadgetText = NULL;
  671.       tgad->GadgetID   = CLASS_LIST+i;
  672.       uly += global.eheight;
  673.    }
  674.  
  675.    list->sborder = list->strgad[0]->GadgetRender;
  676.    list->strgad[0]->GadgetRender = NULL;
  677.  
  678.    /* Undo the damage we did to the base object */
  679.    list->base.title = savetitle;
  680.    list->base.gadget = gad;
  681.  
  682.    reset_list_object(list, -1);
  683.  
  684.    return(uly+global.listextra);
  685. }
  686.  
  687. /***********************************************************************************
  688.  * Procedure: layout_gadgets
  689.  * Synopsis:  gadlist = layout_gadgets(objlist, group, ulx, yly, width);
  690.  * Purpose:   Create all the appropriate gadgetry and image structures for a list
  691.  *            of gadgets.
  692.  ***********************************************************************************/
  693. struct GADLIST *layout_gadgets(struct G_OBJECT *objlist,
  694.                                int group,
  695.                                int ulx, int uly,
  696.                                int width
  697.                               )
  698. {
  699.    struct Gadget *gad;
  700.    struct IntuiText *itext, *itext1;
  701.    int ilen;
  702.    struct G_OBJECT *obj;
  703.    struct GADLIST *gadlist;
  704.  
  705.    gadlist = (struct GADLIST *)get_mem(sizeof(struct GADLIST));
  706.    if (gadlist == NULL) return(NULL);
  707.  
  708.    /* First we need to lay out the gadgets on the left side of the window */
  709.    for(obj = objlist; obj != NULL; obj = obj->next)
  710.    {
  711.       /* Create a gadget structure and an associated intuitext structure to be */
  712.       /* Layed out on the screen                                               */
  713.       gad = create_gadget(gadlist, obj, ulx, uly, width);
  714.  
  715.       if (gad == NULL) return(gadlist);
  716.  
  717.       itext = (struct IntuiText *)(gad+1);
  718.  
  719.       uly += gad->Height;
  720.  
  721.       ilen = IntuiTextLength(itext);
  722.       switch(obj->class)
  723.       {
  724.          case CLASS_STRING:
  725.             gad->LeftEdge   += global.titsize[group];
  726.             gad->Width       = global.cycsize[group];
  727.             itext->LeftEdge  = -ilen;
  728.             setup_string_gadget(gad, CLASS_STRING);
  729.             break;
  730.  
  731.          case CLASS_GROUP:
  732.             gad->GadgetRender = global.cycborder[group];
  733.             gad->GadgetType   = BOOLGADGET;
  734.             gad->Width        = global.cycsize[group];
  735.             gad->LeftEdge    += global.titsize[group] / 2;
  736.             itext->LeftEdge   = (CYC_ICON_WIDTH+gad->Width-ilen)/2;
  737.             uly  += MARGIN_TOP;
  738.             break;
  739.  
  740.          case CLASS_CYCLE:
  741.             gad->GadgetRender = global.cycborder[group];
  742.             gad->GadgetType = BOOLGADGET;
  743.             gad->LeftEdge   += global.titsize[group];
  744.             gad->Width       = global.cycsize[group];
  745.             itext->LeftEdge  = -ilen;
  746.             itext1 = (struct IntuiText *)get_mem(sizeof(struct IntuiText));
  747.             if (itext1 == NULL) return(gadlist);
  748.             itext1->FrontPen  = 1;
  749.             itext1->BackPen   = 0;
  750.             itext1->DrawMode  = JAM1;
  751.             itext1->LeftEdge  = 0;
  752.             itext1->TopEdge   = 3;
  753.             itext1->ITextFont = &global.ri.TextAttr;
  754.             itext1->IText     = ((struct G_CYCLE *)obj)->curval->title;
  755.             itext1->NextText  = NULL;
  756.             itext1->LeftEdge  = (CYC_ICON_WIDTH+gad->Width-IntuiTextLength(itext1))/2;
  757.  
  758.             itext->NextText   = itext1;
  759.             itext1->IText     = ((struct G_CYCLE *)obj)->curval->title;
  760.             break;
  761.  
  762.          case CLASS_CHECK:
  763.             gad->GadgetType   = BOOLGADGET;
  764.             gad->Width        = CHECK_WIDTH;
  765.             gad->Height       = CHECK_HEIGHT;
  766.             gad->Flags        = GADGHIMAGE;
  767.             if (obj->state)   gad->Flags |= SELECTED;
  768.             gad->Activation  |= TOGGLESELECT;
  769.             gad->GadgetRender = global.checkborder[0];
  770.             gad->SelectRender = global.checkborder[1];
  771.             itext->LeftEdge  += CHECK_WIDTH + 4;
  772.             break;
  773.  
  774.          case CLASS_LIST:
  775.             uly = setup_list_object(gadlist, gad);
  776.             if (uly <= 0) return(gadlist);
  777.             break;
  778.  
  779.          default:
  780.             gad->GadgetType = BOOLGADGET;
  781.             break;
  782.       }
  783.    }
  784.    return(gadlist);
  785. }
  786.  
  787. /***********************************************************************************
  788.  * Procedure: build_border
  789.  * Synopsis:  Border = build_border(width, height, mode)
  790.  * Purpose:   Build an return a set of drawing vectors that represent a button of
  791.  *            width and height.  Mode can be either MODE_OUT or MODE_IN
  792.  ***********************************************************************************/
  793. struct Border *build_border(int width,
  794.                             int height,
  795.                             int mode
  796.                            )
  797. {
  798.    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  799.    /*                                                                             */
  800.    /* Select the colors based on the rendering mode.  For an out box, we will use */
  801.    /* the lighter color on the upper and left sides and the darker color on the   */
  802.    /* other two sides.  In an in box, the choice is reversed.                     */
  803.    /*   (x,y)                                                5                    */
  804.    /*   1****************************************************.2                   */
  805.    /*    **4                                               3..                    */
  806.    /*    **                                                 ..                    */
  807.    /*    **                                                 ..                    */
  808.    /*    **                                                 ..                    */
  809.    /*    **                                                 ..                    */
  810.    /*    **3 5                                             4..                    */
  811.    /*   2*....................................................1                   */
  812.    /*                                                       (x+width, y+height)   */
  813.    /* 0.       0,    0    10.   wd,   ht                                          */
  814.    /* 2.       0,   ht    12.   wd,    0                                          */
  815.    /* 4.       1, ht-1    14. wd-1,    1                                          */
  816.    /* 6.       1,    0    16. wd-1,   ht                                          */
  817.    /* 8.    wd-1,    0    18.    1,   ht                                          */
  818.    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  819.  
  820.    struct Border *border, *border1;
  821.    short *vecs;
  822.    int i;
  823.  
  824.    static short inits[] = { 0, 0,   0, 0,   1,-1,   1, 0,  -1, 0,
  825.                             0, 0,   0, 0,  -1, 1,  -1, 0,   1, 0};
  826.  
  827. #define VEC_COUNT 5
  828. #define SINGLEUNIT (sizeof(struct Border)+sizeof(inits))
  829.  
  830.    width--;
  831.    height--;
  832.    border = (struct Border *)get_mem(2*SINGLEUNIT);
  833.    if (border == NULL) return(NULL);
  834.  
  835.    border1 = border+1;
  836.    vecs = (short *)(border+2);
  837.    border->NextBorder = border1;
  838.    border->DrawMode   = JAM1;
  839.    border->Count      = VEC_COUNT;
  840.    border->XY         = vecs;
  841.  
  842.    border1->DrawMode  = JAM1;
  843.    border1->Count     = VEC_COUNT;
  844.    border1->XY        = vecs + (2*VEC_COUNT);
  845.  
  846.    memcpy((char *)vecs, (char *)inits, sizeof(inits));
  847.    for(i = 8; i < 17; i += 2) vecs[i] += width;
  848.    vecs[3]  += height;
  849.    vecs[5]  += height;
  850.    vecs[11] += height;
  851.    vecs[17] += height;
  852.    vecs[19] += height;
  853.  
  854.    if (mode == MODE_OUT)
  855.    {
  856.       border1->FrontPen = global.ri.Shadow;
  857.       border->FrontPen = global.ri.Highlight;
  858.    }
  859.    else
  860.    {
  861.       border1->FrontPen = global.ri.Highlight;
  862.       border->FrontPen  = global.ri.Shadow;
  863.    }
  864.    return(border);
  865. }
  866.  
  867. /***********************************************************************************
  868.  * Procedure: init_gad_sizes
  869.  * Synopsis:  rc = init_gad_sizes();
  870.  * Purpose:   Calculate and initialize all the imagery structures
  871.  ***********************************************************************************/
  872. int init_gad_sizes()
  873. {
  874.    struct G_GROUP     *groups;
  875.    int i;
  876.    int width, height, fudgesize;
  877.    struct Border *border;
  878.    /* * * * * * * * * * * * * * * * * * * * * * * * * * */
  879.    /*                                                   */
  880.    /*              11111111                11111111     */
  881.    /*    012345678901234567      012345678901234567     */
  882.    /*    =================#      =================# 0   */
  883.    /*    ||......23......##      ||..18......54..## 1   */
  884.    /*    ||......##......##      ||..##......##..## 2   */
  885.    /*    ||.....####.....##      ||...##....##...## 3   */
  886.    /*    ||....##76##....##      ||....##76##....## 4   */
  887.    /*    ||...##....##...##      ||.....####.....## 5   */
  888.    /*    ||..##......##..##      ||......##......## 6   */
  889.    /*    ||..18......54..##      ||......23......## 7   */
  890.    /*    |#################      |################# 8   */
  891.    /*                                                   */
  892.    /* * * * * * * * * * * * * * * * * * * * * * * * * * */
  893.    static short Up_Vectors[] = { 4,6,  8,2,  9,2, 13,6, 12,6,  9,3,  8,3,  5,6 };
  894.    static short Dn_Vectors[] = { 4,2,  8,6,  9,6, 13,2, 12,2,  9,5,  8,5,  5,2 };
  895.  
  896.    /* * * * * * * * * * * * * * * * * * */
  897.    /*              11111111112222       */
  898.    /*    012345678901234567890134       */
  899.    /*    ========================== 0   */
  900.    /*    ||.....7.....8..........   1   */
  901.    /*    ||.....#######......#|..   2   */
  902.    /*    ||...5##.....##d....#|..   3   */
  903.    /*    ||....##.....##.....#|..   4   */
  904.    /*    ||....##..a######b..#|..   5   */
  905.    /*    ||....##....####....#|..   6   */
  906.    /*    ||....##....9##c....#|..   7   */
  907.    /*    ||....##............#|..   8   */
  908.    /*    ||...4##6...0##1....#|..   9   */
  909.    /*    ||.....#######......#|..   10  */
  910.    /*    ||.....3.....2..........   11  */
  911.    /*    |########################  12  */
  912.    /*                                   */
  913.    /* * * * * * * * * * * * * * * * * * */
  914.    static short Cycle_Vectors[] = { 13, 9,  14, 9,  13,10,   7,10,   6, 9,
  915.                                      6, 3,   7, 9,   7, 2,  13, 2,  13, 7,
  916.                                     11, 5,  16, 5,  14, 7,  14, 3, };
  917.    static short Cycle_Line1[]   = { 20, 2,  20,11};
  918.    static short Cycle_Line2[]   = { 21, 2,  21,11};
  919.  
  920.    static short Check_Vectors[] = { 19, 2,  17, 2,  11, 8,   8, 5,   7, 5,
  921.                                     10, 8,   9, 5,  12, 8,  18, 2 };
  922.  
  923.    /* Make two passes attempting to layout the items.  The first time we will use */
  924.    /* Whatever the prevailing font is.  If this doesn't work, we will switch to a */
  925.    /* Simple TOPAZ80 and try again.  Only if that fails will we give up.          */
  926.    for(i = 2; i >= 0; i--)
  927.    {
  928.       int dwid,nwid;
  929.       global.cycsize[0] = global.cycsize[1] = 0;
  930.       global.titsize[0] = global.titsize[1] = 0;
  931.       global.stxtwid = text_width("0");
  932.       nwid = text_width(global.button[BUTTON_NEW].title);
  933.       dwid = text_width(global.button[BUTTON_DEL].title);
  934.       global.lgadwid = (dwid > nwid ? dwid : nwid) + PROP_WIDTH + 3*DVBAR;
  935.  
  936.       fudgesize = 0;
  937.       get_cycle_sizes(global.objects, global.titsize, global.cycsize, &fudgesize);
  938.       if ((global.cycsize[0] + global.titsize[0]) < fudgesize)
  939.          global.cycsize[0] = fudgesize - global.titsize[0];
  940.  
  941.       fudgesize = 0;
  942.       for(groups = global.groups; groups != NULL;
  943.           groups = (struct G_GROUP *)groups->base.next)
  944.       {
  945.          get_cycle_sizes(groups->objects, global.titsize+1, global.cycsize+1,
  946.                          &fudgesize);
  947.          if (global.cycsize[1] < (text_width(groups->base.title)
  948.                                     + CYC_ICON_WIDTH + 2*DVBAR))
  949.             global.cycsize[1] = text_width(groups->base.title)
  950.                                     + CYC_ICON_WIDTH + 2*DVBAR;
  951.       }
  952.       if ((global.cycsize[1] + global.titsize[1]) < fudgesize)
  953.          global.cycsize[1] = fudgesize - global.titsize[1];      
  954.  
  955.       global.iheight = global.ri.TextAttr.ta_YSize+DHBAR;
  956.       if (global.iheight < global.ri.FontSize)
  957.          global.iheight = global.ri.FontSize;
  958.       if (i)
  959.       {
  960.          global.iheight += 4; /* Account for decent margins on the rendering */
  961.          global.eheight = global.ri.FontSize + 2*DHBAR;
  962.          global.listextra = 0;
  963.       }
  964.       else
  965.       {
  966.          global.iheight += 2; /* Account for decent margins on the rendering */
  967.          global.eheight = global.ri.FontSize + DHBAR + HBAR;
  968.          global.listextra = 1;
  969.       }
  970.  
  971.       /* We have the totals for everything, let's figure out how */
  972.       /* big the final thing is going to be.                     */
  973.       height = ((global.maxsize+1)*global.iheight) +
  974.                2*global.listextra +
  975.                global.ri.WindowTitle +
  976.                global.ri.WindowBottom + MARGIN_MID;
  977.       width  = global.cycsize[0]+global.cycsize[1] +
  978.                global.titsize[0]+global.titsize[1] +
  979.                global.ri.WindowLeft +
  980.                global.ri.WindowRight +
  981.                MARGIN_SEP + MARGIN_LEFT + MARGIN_RIGHT;
  982.  
  983.       if ((height <= global.ri.ScreenHeight) &&
  984.           (width  <= global.ri.ScreenWidth)) break;
  985.  
  986.       if (i==0)
  987.       {
  988.          /* We couldn't fit what they wanted on the screen, so error out with */
  989.          /* A message indicating the problem.  We really shouldn't see this   */
  990.          /* happen much, but at least account for it.                         */
  991.          sprintf(global.title, "Bad Layout W:%d>%d H:%d>%d",
  992.                                 width, global.ri.ScreenWidth,
  993.                                 height, global.ri.ScreenHeight);
  994.          return(1);
  995.       }
  996.       /* Set up so we try with Topaz 80 as our default font the second time around */
  997.       global.ri.TextAttr = TOPAZ80;
  998.    }
  999.  
  1000.    /* Now we have calculated sizes for the objects, layout the border structures */
  1001.    for(i = 0; i < 2; i++)
  1002.    {
  1003.       /* Create a border for the cycle gadgets */
  1004.       global.cycborder[i] = build_border(global.cycsize[i],
  1005.                                           global.iheight, MODE_OUT);
  1006.       /* We also need to put in the vectors for the cycle picture */
  1007.       border = (struct Border *)get_mem(4*sizeof(struct Border));
  1008.       if (border == NULL) return(1);
  1009.  
  1010.       border[0].NextBorder = border+1;
  1011.       border[1].NextBorder = border+2;
  1012.       border[2].NextBorder = global.cycborder[i];
  1013.       global.cycborder[i] = border;
  1014.  
  1015.       border[0].DrawMode = JAM1;
  1016.       border[0].Count  = sizeof(Cycle_Vectors)/(2*sizeof(short));
  1017.       border[0].XY = Cycle_Vectors;
  1018.       border[0].FrontPen = 1;
  1019.  
  1020.       border[1].DrawMode = JAM1;
  1021.       border[1].Count  = sizeof(Cycle_Line1)/(2*sizeof(short));
  1022.       border[1].XY = Cycle_Line1;
  1023.       border[1].FrontPen = global.ri.Shadow;
  1024.  
  1025.       border[2].DrawMode = JAM1;
  1026.       border[2].Count  = sizeof(Cycle_Line2)/(2*sizeof(short));
  1027.       border[2].XY = Cycle_Line2;
  1028.       border[2].FrontPen = global.ri.Highlight;
  1029.  
  1030.       global.checkborder[i] = border+3;
  1031.       border[3].NextBorder = build_border(CHECK_WIDTH, CHECK_HEIGHT, MODE_OUT);
  1032.       border[3].DrawMode = JAM1;
  1033.       border[3].Count = sizeof(Check_Vectors)/(2*sizeof(short));
  1034.       border[3].XY = Check_Vectors;
  1035.       border[3].FrontPen = i;
  1036.    }
  1037.  
  1038.    /* Adjust the height of the cycle vectors to the current height */
  1039.    /* See the picture above for these values.  Yes, they are hard  */
  1040.    /* coded magic values, but equates for them don't make a lot of */
  1041.    /* sense in a situation like this.                              */
  1042.    for(i = 0; i < 0x0d; i++)
  1043.    {
  1044.       int extra;
  1045.  
  1046.       extra = global.iheight - 13;
  1047.       if (i > 8)
  1048.       {
  1049.          extra >>= 1;
  1050.       }
  1051.       else if ((i > 6) || (i == 5))
  1052.       {
  1053.          extra = 0;
  1054.       }
  1055.  
  1056.       Cycle_Vectors[1+i*2] += extra;
  1057.    }
  1058.  
  1059.    Cycle_Line2[3] = Cycle_Line1[3] = (global.iheight - 1) - DHBAR;
  1060.  
  1061.    {
  1062.       int bheight;
  1063.       bheight = (MAX_LIST*global.eheight) - (2*ARR_HEIGHT) + global.listextra;
  1064.       border = build_border(PROP_WIDTH, bheight, MODE_OUT);
  1065.       if (border == NULL) return(1);
  1066.  
  1067.       border->TopEdge -= bheight;
  1068.       border->NextBorder->TopEdge -= bheight;
  1069.    }
  1070.  
  1071.    global.arrowborder[0].NextBorder = build_border(PROP_WIDTH, ARR_HEIGHT, MODE_OUT);
  1072.    global.arrowborder[1].NextBorder = border;
  1073.    border->NextBorder->NextBorder = global.arrowborder[0].NextBorder;
  1074.  
  1075.    global.arrowborder[0].DrawMode = JAM1;
  1076.    global.arrowborder[0].Count  = sizeof(Dn_Vectors)/(2*sizeof(short));
  1077.    global.arrowborder[0].XY = Dn_Vectors;
  1078.    global.arrowborder[0].FrontPen = 1;
  1079.  
  1080.    global.arrowborder[1].DrawMode = JAM1;
  1081.    global.arrowborder[1].Count  = sizeof(Up_Vectors)/(2*sizeof(short));
  1082.    global.arrowborder[1].XY = Up_Vectors;
  1083.    global.arrowborder[1].FrontPen = 1;
  1084.  
  1085.    /* Everything worked out fine, let us set the height of the window */
  1086.    global.width = width;
  1087.    global.height = height;
  1088.  
  1089.    /* Now sizes for special string gadgets            */
  1090.    global.titsize[2] = text_width(global.text[TEXT_FILEREQ]);
  1091.    global.cycsize[2] = global.width - global.ri.WindowLeft
  1092.                         - global.ri.WindowRight - 100;
  1093.  
  1094.    return(0);
  1095. }
  1096.  
  1097. /***********************************************************************************
  1098.  * Procedure: get_cycle_sizes
  1099.  * Synopsis:  get_cycle_sizes(objlist, &titsize, &cycsize)
  1100.  * Purpose:   Calculate the base sizes for different types of objects.
  1101.  *            We need to calculate the width for CYCLE titles and size for cycles
  1102.  *            Everything else has a fixed size to be used anyway.
  1103.  ***********************************************************************************/
  1104. void get_cycle_sizes(struct G_OBJECT *objlist,
  1105.                     int *titsize,
  1106.                     int *cycsize,
  1107.                     int *fudgesize)
  1108. {
  1109.    int wid;
  1110.    struct G_OBJECT *obj;
  1111.    struct G_CYCLE *cyc;
  1112.    struct G_VALUE *val;
  1113.  
  1114. /*
  1115.    *titsize -= DVBAR;
  1116.    *cycsize -= CYC_ICON_WIDTH+DVBAR;
  1117. */
  1118.  
  1119.    /* First we need to lay out the gadgets on the left side of the window */
  1120.    for(obj = objlist; obj != NULL; obj = obj->next)
  1121.    {
  1122.       switch(obj->class)
  1123.       {
  1124.          case CLASS_CYCLE:
  1125.             /* go through and get all the cycle values */
  1126.             cyc = (struct G_CYCLE *)obj;
  1127.             set_cyc_state(cyc, cyc->values);
  1128.             for(val = cyc->values; val != NULL; val = val->next)
  1129.             {
  1130.                wid = text_width(val->title) + CYC_ICON_WIDTH+DVBAR;
  1131.                if (val->string)
  1132.                {
  1133.                   int num;
  1134.                   num = string_width(val->option, 3);
  1135.                   wid += (global.stxtwid * num) + DVBAR;
  1136.                }
  1137.                if (wid > *cycsize) *cycsize = wid;
  1138.             }
  1139.             wid = text_width(obj->title) + DVBAR;
  1140.             if (wid > *titsize) *titsize = wid;
  1141.             break;
  1142.          case CLASS_STRING:
  1143.             wid = text_width(obj->title);
  1144.             if (wid > *titsize) *titsize = wid;
  1145.             /* provide a reasonable default string entry area */
  1146.             wid = string_width(((struct G_STRING *)obj)->option, 10);
  1147.             wid = wid * global.stxtwid + 2*DVBAR;
  1148.             if (wid > *cycsize) *cycsize = wid;
  1149.             break;
  1150.          case CLASS_LIST:
  1151.             wid = text_width(obj->title);
  1152.             if (wid > *fudgesize) *fudgesize = wid;
  1153.             wid = string_width(((struct G_LIST *)obj)->option, 10);
  1154.             wid = wid * global.stxtwid + global.lgadwid;
  1155.             if (wid > *fudgesize) *fudgesize = wid;
  1156.             break;
  1157.          case CLASS_CHECK:
  1158.             wid = text_width(obj->title) + CHECK_WIDTH + 2*DVBAR;
  1159.             if (wid > *fudgesize) *fudgesize = wid;
  1160.             break;
  1161.       }
  1162.    }
  1163. /*
  1164.    *titsize += DVBAR;
  1165.    *cycsize += CYC_ICON_WIDTH+DVBAR;
  1166. */
  1167. }
  1168.  
  1169. /***********************************************************************************
  1170.  * Procedure: text_width
  1171.  * Synopsis:  len = text_width(str)
  1172.  * Purpose:   Return the rendered width of a given string
  1173.  ***********************************************************************************/
  1174. int text_width(char *str
  1175.               )
  1176. {
  1177.    struct IntuiText itext;
  1178.  
  1179.    itext.FrontPen  = 1;
  1180.    itext.BackPen   = 0;
  1181.    itext.DrawMode  = JAM1;
  1182.    itext.LeftEdge  = 0;
  1183.    itext.TopEdge   = 1;
  1184.    itext.ITextFont = &global.ri.TextAttr;
  1185.    itext.NextText  = NULL;
  1186.    itext.IText     = str;
  1187.  
  1188.    return(IntuiTextLength(&itext));
  1189. }
  1190.  
  1191. /**********************************************************************************
  1192.  * Procedure: string_width
  1193.  * Synopsis:  len = string_width(str)
  1194.  * Purpose:   Return the size of a string specification %ns, default n = 3
  1195.  *********************************************************************************/
  1196. int string_width(char *str, int def_width)
  1197. {
  1198.    char *p;
  1199.    int num;
  1200.  
  1201.    p = strchr(str, '%');
  1202.    num = 0;
  1203.    if (p)
  1204.    {
  1205.       p++;
  1206.       while ((*p >= '0') && (*p <= '9'))
  1207.          num = (num * 10) + *p++ - '0';
  1208.    }
  1209.    
  1210.    if (num <= 0) num = def_width;
  1211.    return (num + 1);
  1212. }
  1213.